    var ViewClass = function(formater, html) {
        this.html = html;
        this.formater = formater;
    };

    var PresenterClass = function(outputDirectory,view) {
        this.view = view;
        this.view.presenter = this;
        this.outputDirectory = outputDirectory;
        this.periodForChart = undefined;
        this.imageFile = undefined;
        this.imageStatFile = undefined;
        this.info = {};
        this.config = {};
    };
    
    var FormaterClass = function() {
    };

    var ServiceFormaterClass = function() {
        
    };
        
(function() {
    
    // //////////////////////////////////////////////////////////////////////////////////////
    // /// View /////////////////////////////
    // /////////////////////////////////////////////////////////////////////////////////////

    ViewClass.prototype.initUI = function() {
        $('input:radio[name=sortedBy_radio]:first').attr('checked',true);
        $('input:radio[name=period_radio]:first').attr('checked',true);
        $('#monthsRadioText').html('Last ' + this.presenter.config.amountOfMonthsOnMonthsChart + ' months');
        $('#weeksRadioText').html('Last ' + this.presenter.config.amountOfWeeksOnWeeksChart + ' weeks');
        $('#daysRadioText').html('Last ' + this.presenter.config.amountOfDaysOnDaysChart + ' days');
        $('#hoursRadioText').html('Last ' + this.presenter.config.amountOfHoursOnHoursChart + ' hours');
        this.html.fadeIn(1000);
    }    
    
    ViewClass.prototype.updateRows = function(data) {
        var colors = [ {
            odd : '#E0E000',
            even : '#F0F000'
        }, {
            odd : '#00E0E0',
            even : '#00F0F0'
        }, {
            odd : '#E000E0',
            even : '#F000F0'
        }, {
            odd : '#E0A0E0',
            even : '#F0B0F0'
        },
        {
            odd : '#E0E0E0',
            even : '#F0F0F0'
        },
        {
            odd : '#00E000',
            even : '#00F000'
        }];
        var row = '<table id="mainTable" cellpadding="0" cellspacing="0" style="width: 100%;">' + '<tr style="font-weight: bold;">' 
                + '<td style="padding: 5px 10px; text-align: center; background: #00D0D0;">amount of requests</td>'
                + '<td style="padding: 5px 10px; text-align: center; background: #D000D0;">max. response time</td>' + '<td style="padding: 5px 10px; text-align: center; background: #D0A0D0; width: 150px">when it was happened</td>'
                + '<td style="padding: 5px 10px; text-align: center; background: #D0D0D0;">sum all response times</td>'
                + '<td style="padding: 5px 10px; text-align: center; background: #D0D000;">service name</td>'
                + '<td style="padding: 5px 10px; text-align: center; background: #00D000;">Last <span style="white-space: nowrap;">' + this.presenter.config.amountOfMonthsOnMonthsChart + ' months</span></td>'
                + '<td style="padding: 5px 10px; text-align: center; background: #00D000;">Last <span style="white-space: nowrap;">' + this.presenter.config.amountOfWeeksOnWeeksChart + ' weeks</span></td>'
                + '<td style="padding: 5px 10px; text-align: center; background: #00D000;">Last <span style="white-space: nowrap;">' + this.presenter.config.amountOfDaysOnDaysChart + ' days</span></td>'
                + '<td style="padding: 5px 10px; text-align: center; background: #00D000;">Last <span style="white-space: nowrap;">' + this.presenter.config.amountOfHoursOnHoursChart + 'hours</span></td>' + '</tr>';

        var step = 'odd';
        var presenter = this.presenter;
        var thisView = this;
        $.each(data, function(key, val) {
            if (step == 'odd') {
                step = 'even';
            } else {
                step = 'odd';
            }
            
            row += '<tr>';
            row += '<td style="padding: 5px 10px; background: ' + colors[1][step] + '; text-align: right; white-space: nowrap;">' + val.count + '</td>';
            row += '<td style="padding: 5px 10px; background: ' + colors[2][step] + '; text-align: right; white-space: nowrap;">' + thisView.formater.formatTimePeriod(val.maxRespTime) + '</td>';
            row += '<td style="padding: 5px 10px; background: ' + colors[3][step] + '; text-align: right; white-space: nowrap;">' + val.whenMaxRespTime + '</td>';
            row += '<td style="padding: 5px 10px; background: ' + colors[4][step] + '; text-align: right; white-space: nowrap;">' + thisView.formater.formatTimePeriodWithDays(val.spentTime) + '</td>';
            row += '<td style="padding: 5px 10px; background: ' + colors[0][step] + '; white-space: nowrap;">' + thisView.formater.serviceFormat(val.category) + '</td>';
            
            if (presenter.info['Months'].data[key]) {
                row += '<td style="padding: 5px 10px; background: ' + colors[5][step] + '; text-align: right;"><a href="javascript:  presenter.showChart(\'Months\', \'' + val.trafficFileName + '\');" style="white-space: nowrap;">' + presenter.config.amountOfMonthsOnMonthsChart + ' months</a></td>';
            } else {
                row += '<td style="padding: 5px 10px; background: ' + colors[5][step] + '; text-align: right; white-space: nowrap;">no data</td>';
            }

            if (presenter.info['Weeks'].data[key]) {
                row += '<td style="padding: 5px 10px; background: ' + colors[5][step] + '; text-align: right;"><a href="javascript:  presenter.showChart(\'Weeks\', \'' + val.trafficFileName + '\');" style="white-space: nowrap;">' + presenter.config.amountOfWeeksOnWeeksChart + ' weeks</a></td>';
            } else {
                row += '<td style="padding: 5px 10px; background: ' + colors[5][step] + '; text-align: right; white-space: nowrap;">no data</td>';
            }

            if (presenter.info['Days'].data[key]) {
                row += '<td style="padding: 5px 10px; background: ' + colors[5][step] + '; text-align: right;"><a href="javascript:  presenter.showChart(\'Days\', \'' + val.trafficFileName + '\');" style="white-space: nowrap;">' + presenter.config.amountOfDaysOnDaysChart + ' days</a></td>';
            } else {
                row += '<td style="padding: 5px 10px; background: ' + colors[5][step] + '; text-align: right; white-space: nowrap;">no data</td>';
            }

            if (presenter.info['Hours'].data[key]) {
                row += '<td style="padding: 5px 10px; background: ' + colors[5][step] + '; text-align: right;"><a href="javascript:  presenter.showChart(\'Hours\', \'' + val.trafficFileName + '\');" style="white-space: nowrap;">' + presenter.config.amountOfHoursOnHoursChart + ' hours</a></td>';
            } else {
                row += '<td style="padding: 5px 10px; background: ' + colors[5][step] + '; text-align: right; white-space: nowrap;">no data</td>';
            }
            row += '</tr>';
        });
        row += '</table>';
        $('#mainTable').remove();
        $('#mainTableContainer').append(row);
    }

    ViewClass.prototype.updateImage = function(periodForChart, imgSrc, imgProbabilitySrc) {
        if ($('#imageOne').length == 0){
            $('#imageContainer').append('<img id="imageOne" /><BR>');
        }        
        $('#imageOne').attr('src', imgSrc);
        
        if ($('#imageTwo').length == 0){
            $('#imageContainer').append('<img id="imageTwo" />');
        } 
        if (periodForChart == 'Hours') {
            $('#imageTwo').hide();
        } else {
            $('#imageTwo').attr('src', imgProbabilitySrc);
            $('#imageTwo').show();
        }
        
    }

    ViewClass.prototype.updateLabel = function(configName, from, to) {
        $('#configName').html(configName);
        $('#from').html(from);
        $('#to').html(to);
    }
    
    ViewClass.prototype.getSortedBy = function() {
        return $('input:radio[name=sortedBy_radio]:checked').val();
    }

    ViewClass.prototype.getPeriod = function() {
        return $('input:radio[name=period_radio]:checked').val();
    }

    
    // //////////////////////////////////////////////////////////////////////////////////////
    // /// Presenter /////////////////////////////
    // /////////////////////////////////////////////////////////////////////////////////////

    PresenterClass.prototype.init = function() {
        this.view.initUI();
    }
    
    PresenterClass.prototype.loadJSON = function() {
        var result;

        result = $.ajax({
            url : this.outputDirectory + '/GeneralStatisticConfiguration.json',
            data : {},
            async : false
        }).responseText;
        this.config = eval('(' + result + ')');        
        
        result = $.ajax({
            url : this.outputDirectory + '/Months/MonthsStatistic.json',
            data : {},
            async : false
        }).responseText;
        this.info['Months'] = eval('(' + result + ')');

        result = $.ajax({
            url : this.outputDirectory + '/Weeks/WeeksStatistic.json',
            data : {},
            async : false
        }).responseText;
        this.info['Weeks'] = eval('(' + result + ')');

        result = $.ajax({
            url : this.outputDirectory + '/Days/DaysStatistic.json',
            data : {},
            async : false
        }).responseText;
        this.info['Days'] = eval('(' + result + ')');

        this.info.Hours_MaxRespTime = eval('(' + result + ')');
        result = $.ajax({
            url : this.outputDirectory + '/Hours/HoursStatistic.json',
            data : {},
            async : false
        }).responseText;
        this.info['Hours'] = eval('(' + result + ')');

    }

    PresenterClass.prototype.update = function() {
        
        var tmp_kv = [];
        var sortedBy = this.view.getSortedBy();
        var period = this.view.getPeriod();
        $.each(this.info[period].data, function(key,val){
            tmp_kv.push({k: key, v: val[sortedBy]});
        });
        tmp_kv.sort(function(a,b){
            if (typeof a.v == 'number' && typeof b.v == 'number'){
                return (b.v - a.v);
            } else {
                var x = a.v;
                var y = b.v; 
                x = x.toLowerCase();
                y = y.toLowerCase();
                return ((x < y) ? -1 : ((x > y) ? 1 : 0));
            }
        });
        var sortedData = {};
        for (var index in tmp_kv){
            var kk = tmp_kv[index].k;
            var vv = tmp_kv[index].v;
            sortedData[kk] = this.info[period].data[kk];
        };   
        
        this.info[period].data = sortedData;
        this.view.updateRows(sortedData);

        if (this.imageFile != undefined){
            var imgSrc = this.outputDirectory + '/' + this.periodForChart + '/' + this.imageFile + '.png';
            var imgSrcProbability = this.outputDirectory + '/' + this.periodForChart + '/' + this.imageFile + '_probability.png';
            this.view.updateImage(this.periodForChart, imgSrc, imgSrcProbability);
        }
        this.view.updateLabel(this.config.configName, this.info[period].from, this.info[period].to);

    }

    PresenterClass.prototype.showChart = function(periodForChart, chartFile) {
        this.periodForChart = periodForChart;
        this.imageFile = chartFile;
        this.update();
    }

    // //////////////////////////////////////////////////////////////////////////////////////
    // /// Formatters /////////////////////////////
    // /////////////////////////////////////////////////////////////////////////////////////    

    FormaterClass.prototype.formatTimePeriod = function(time) {
        var rest = Math.floor(time);
        
        var ms = rest % 1000;
        var msPrefix='';
        if (ms<100){
            msPrefix='0';
            if (ms<10){
                msPrefix='00';
            }
        }
        var rest = Math.floor(rest / 1000);
        
        var sec = rest % 60;
        var secPrefix='';
        if (sec<10){
            secPrefix='0';
        }       
        var min = Math.floor(rest / 60);
        
        var minPrefix='';
        if (min<10){
            minPrefix='0';
        }
        return String(minPrefix + min + ':' + secPrefix + sec + '.' + msPrefix + ms);
    }
    
    FormaterClass.prototype.formatTimePeriodWithDays = function(time) {
        var rest = Math.floor(time);
        var ms = rest % 3600000;
        var rest = Math.floor(rest / 3600000);
        
        var hour = rest % 24;
        var hourPrefix='';
        if (hour<10){
            hourPrefix='0';
        }
        var days = Math.floor(rest / 24);        
        return String(days + 'd' + hourPrefix + hour + ':'+ this.formatTimePeriod(ms));
    } 
    
    FormaterClass.prototype.serviceFormat = function(serviceName) {
        return serviceName;
    }    
    
    ServiceFormaterClass.prototype = new FormaterClass();
    
    ServiceFormaterClass.prototype.serviceFormat = function(serviceName) {
        var separator="|";
        if (serviceName.indexOf(separator) > -1){
            return serviceName.replace(separator,separator + "<B>") + "</B>";
        } else {
            return serviceName;
        }
    }
    
})()